package com.liao.badminton.service.impl;

import cn.hutool.core.io.FileUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.liao.badminton.code.*;
import com.liao.badminton.code.util.CheckUtil;
import com.liao.badminton.dto.FileShardDto;
import com.liao.badminton.entity.FileShard;
import com.liao.badminton.mapper.FileShardMapper;
import com.liao.badminton.service.FileShardService;
import com.liao.badminton.code.util.Base64ToMultipartFile;
import com.liao.badminton.code.util.MyFileUtil;
import com.liao.badminton.vo.FileShardVo;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @author liaocheng
 * @date 2023-11-11
 * description:文件
 */
@Component
public class FileShardServiceImpl extends ServiceImpl<FileShardMapper, FileShard> implements FileShardService {
    /**
     * 新增
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED, timeout = 10, rollbackFor = Exception.class)
    public ResponseRest<Long> saveFileShard(FileShardDto param) throws ProjectException {
        CheckUtil.checkValue(param, "param");
        FileShard save = param.invertEntity();
        this.save(save);
        return ResponseRest.suc("saveFileShard", FileShardVo.invertToVo(save));
    }

    /**
     * 修改
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED, timeout = 10, rollbackFor = Exception.class)
    public ResponseRest<Boolean> updateFileShard(FileShardDto param) throws ProjectException {
        FileShard entity = param.invertEntity();
        CheckUtil.checkValue(param.getId(), "主键id不能为空");
        this.updateById(entity);
        return ResponseRest.suc("updateFileShard");
    }

    /**
     * 删除
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED, timeout = 10, rollbackFor = Exception.class)
    public ResponseRest<Boolean> deletesFileShard(FileShardDto param) throws ProjectException {
        CheckUtil.checkValue(param, "param");
        CheckUtil.checkValue(param.getDelIds(), "delIds");
        List<FileShard> fileShards = this.listByIds(param.getDelIds());
        this.removeByIds(param.getDelIds());
        if (!fileShards.isEmpty()) {
            fileShards.stream().parallel().forEach(entity -> {
                FileUtil.del(entity.getPath());
            });
        }

        return ResponseRest.suc("deletesFileShard");
    }


    /**
     * 查询列表
     */
    @Override
    public ResponseRest findFileShardByPageParam(PageParam<FileShardDto> pageParam) throws ProjectException {
        CheckUtil.checkValue(pageParam, "PageParam");
        ResponseRest resp = ResponseRest.suc("findFileShardByPageParam");
        PageHelper.startPage(pageParam.getCurrent(), pageParam.getSize());
        FileShardDto args = pageParam.getArgs();
        LambdaQueryWrapper<FileShard> query = new LambdaQueryWrapper<>();
        //query.like(UserInfo::getUserName, args.getUserName());
        List<FileShard> list = this.list(query);
        List<FileShardVo> collect = list.stream().parallel().map(entity -> FileShardVo.invertToVo(entity)).collect(Collectors.toList());
        resp.setData(new PageInfo<>(collect));
        return resp;
    }

    @Override
    public ResponseRest findDetail(FileShardDto param) throws ProjectException {
        Long id = param.getId();
        FileShard db = null;
        if (id != null) {
            db = this.getById(id);
        } else if (param.getFileMd() != null) {
            LambdaQueryWrapper<FileShard> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(FileShard::getFileMd, param.getFileMd());
            db = this.getOne(queryWrapper);
        }
        return ResponseRest.suc("findDetailFileShard", FileShardVo.invertToVo(db));
    }

    /**
     * 分片上传
     *
     * @param shard
     * @param fileShard
     * @return
     */
    @Override
//    @Transactional(propagation = Propagation.REQUIRED, timeout = 10, rollbackFor = Exception.class)
    public ResponseRest uploadFileShard(MultipartFile shard, FileShardDto fileShard) {
        // 文件保存到本地目录下
        String fileMd = fileShard.getFileMd();
        String suffix = fileShard.getSuffix();
        Integer shardIndex = fileShard.getShardIndex();
        Integer shardTotal = fileShard.getShardTotal();
        String name = fileShard.getName();
        FileShard invertEntity = fileShard.invertEntity();
        Integer shardSize = fileShard.getShardSize();
        String filePath = MyFileUtil.getBasePathMerge() + fileMd + "." + suffix + "." + shardIndex;

        // 数据入库操作
        LambdaQueryWrapper<FileShard> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(FileShard::getFileMd, fileMd);
        FileShard updateFileEntity = new FileShard();
        // 说明不是第一次上传,需要更新当前上传的分片数量
        updateFileEntity.setShardIndex(shardIndex);
        updateFileEntity.setPath(filePath);
        //base64上传没有这个，改分片上传更新一下
        updateFileEntity.setShardTotal(shardTotal);
        updateFileEntity.setShardSize(shardSize);
        FileShard one = this.getOne(queryWrapper);
        if (one != null && Objects.equals(one.getShardIndex(), shardTotal)) {
            invertEntity = one;
            return ResponseRest.suc("uploadFileShard", FileShardVo.invertToVo(invertEntity));
        }
        File dest = new File(filePath);
        try {
            shard.transferTo(dest);
        } catch (IOException e) {
            e.printStackTrace();
            ProjectException.newException(RespCodeMessage.PARAM_FILE_UPLOAD_SAVE);
        }
        // 合并文件操作;如果只有一个分片还是要去正面保存的
        if (Objects.equals(shardIndex, shardTotal)) {
            String completePath = this.merge(name, fileMd, suffix, shardTotal);
            invertEntity.setPath(completePath);
            updateFileEntity.setPath(completePath);
            if (one != null) {
                invertEntity.setShardIndex(shardIndex);
                this.update(updateFileEntity, queryWrapper);
            }
        }
        if (one != null && !Objects.equals(shardIndex, shardTotal)) {
            this.update(updateFileEntity, queryWrapper);
            invertEntity.setShardIndex(shardIndex);
            invertEntity.setId(one.getId());
            invertEntity.setPath(filePath);
        } else if (one == null) {
            // 第一次上传创建
            if (!Objects.equals(shardIndex, shardTotal)) {
                invertEntity.setPath(filePath);
            }
            this.save(invertEntity);
        }
        return ResponseRest.suc("uploadFileShard", FileShardVo.invertToVo(invertEntity));
    }

    /**
     * 对上传的文件片段合并操作
     *
     * @param key
     * @param suffix
     * @param shardTotal
     * @throws FileNotFoundException
     */
    private String merge(String name, String key, String suffix, Integer shardTotal) {

        String path = MyFileUtil.getBasePath() + name;
        try {
            File newFile = new File(path);
            FileOutputStream outputStream = new FileOutputStream(newFile, true);//文件追加写入
            FileInputStream fileInputStream = null;//分片文件
            byte[] byt = new byte[10 * 1024 * 1024];
            int len;
            try {
                for (int i = 0; i < shardTotal; i++) {
                    fileInputStream = new FileInputStream(new File(MyFileUtil.getBasePathMerge() + key + "." + suffix + "." + (i + 1)));
                    while ((len = fileInputStream.read(byt)) != -1) {
                        outputStream.write(byt, 0, len);
                    }
                }
            } catch (Exception e) {
            } finally {
                try {
                    if (fileInputStream != null) {
                        fileInputStream.close();
                    }
                    outputStream.close();
                } catch (Exception e) {
                }
            }
            System.gc();
            Thread.sleep(1000);
            // 删除分片
            for (int i = 0; i < shardTotal; i++) {
                String filePath = MyFileUtil.getBasePathMerge() + key + "." + suffix + "." + (i + 1);
                File file = new File(filePath);
                boolean result = file.delete();
            }

        } catch (Exception e) {
            e.printStackTrace();
            ProjectException.newException(RespCodeMessage.PARAM_FILE_UPLOAD_SAVE);
        }
        return path;
    }

    public ResponseRest bs64Upload(FileShardDto fileShardDto) {
        // 1.将上传的bs64转为图片
        String bs64 = fileShardDto.getFileBs64();
        MultipartFile shard = Base64ToMultipartFile.base64ToMultipart(bs64);
        // 图片保存到本地
        String localPath = MyFileUtil.getBasePath() + fileShardDto.getName();
        File dest = new File(localPath);
        try {
            shard.transferTo(dest);
        } catch (IOException e) {
            e.printStackTrace();
            ProjectException.newException(RespCodeMessage.PARAM_FILE_UPLOAD_SAVE);
        }
        FileShard invertEntity = fileShardDto.invertEntity();
        invertEntity.setPath(localPath);
        this.save(invertEntity);
        return ResponseRest.suc("uploadFileShard", FileShardVo.invertToVo(invertEntity));
    }


}
